package com.coc.ofmylistener.event.spring;

import com.coc.ofmylistener.event.Event;
import com.coc.ofmylistener.event.EventHandler;
import com.coc.ofmylistener.event.EventHandlerManager;
import com.coc.ofmylistener.event.annontation.EventListener;
import com.coc.ofmylistener.event.annontation.EventListeners;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.util.ClassUtils;

import java.lang.reflect.Method;

/**
 *
 */
public class EventHandlerBeanPostProcessor implements BeanPostProcessor , BeanFactoryAware {

    private BeanFactory beanFactory;

    private EventHandlerManager eventHandlerManager;

    public EventHandlerBeanPostProcessor () {}

    public EventHandlerBeanPostProcessor ( EventHandlerManager eventHandlerManager) {
        this.eventHandlerManager = eventHandlerManager;
    }

    /**
     * register eventhandler through spring
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {

        if(bean instanceof EventHandler){
            eventHandlerManager.regsiter((EventHandler)bean);
        }

        Class<?> beanClass = ClassUtils.getUserClass(bean.getClass());
        if (beanClass.getAnnotation(EventListeners.class) == null) {
            return bean;
        }

        for (Method method : beanClass.getMethods()) {
            EventListener listenerAnnotation = method.getAnnotation(EventListener.class);

             if (listenerAnnotation == null) {
                 continue;
             }

             Class<?>[] methodParemterTypes = method.getParameterTypes();

            if (methodParemterTypes == null || methodParemterTypes.length == 0 ) {
                throw new RuntimeException("EventListener method must has at least one paremeter");
            }

            Class<?> eventTpye = methodParemterTypes[0];
            if ( ! Event.class.isAssignableFrom(eventTpye)) {
                throw new RuntimeException("EventListener method parameter must be assignable from " + Event.class);
            }

            EventHandler handler = new SpringEventHandler(eventTpye,beanName,method,beanFactory,listenerAnnotation.asynchronous());
            eventHandlerManager.regsiter(handler);

        }

        return bean;

    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    public void setEventHandlerManager(EventHandlerManager eventHandlerManager) {
        this.eventHandlerManager = eventHandlerManager;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }


}
